/*
 * io.c - 
 */

#include <io.h>
#include <string.h>

/**************/
/** Screen  ***/
/**************/

#define NUM_COLUMNS 80
#define NUM_ROWS    25

Byte x, y=18;

/* Read a byte from 'port' */
Byte inb (unsigned short port)
{
  Byte v;

  __asm__ __volatile__ ("inb %w1,%0":"=a" (v):"Nd" (port));
  return v;
}

//llegim el valor de una posicio on esta mapejada la pantalla
inline Word read_xy(int _x,int _y) 
{
	Word res;
	DWord screen = 0xb8000 + (_y * NUM_COLUMNS + _x) * 2;
  asm("movw (%1), %0" : "=r" (res) : "r"(screen));
	return res;
}

//Escrivim el valor en la posicio x y on esta mapejada la pantalla
inline void print_word_xy(int _x,int _y, Word ch)
{
	DWord screen = 0xb8000 + (_y * NUM_COLUMNS + _x) * 2;
  asm("movw %0, (%1)" : : "r"(ch), "r"(screen)); 
}

//Limpiem la fila row
inline void cleanRow(int row)
{
  int i;
  for (i = 0; i < NUM_COLUMNS; i++)
    printc_xy(i,row,' ');
}

//prec ->(exepcio?) x:[0,NUM_COLUMNS), y:[0,NUM_ROWS)
void printc_xy(int _x, int _y, char _c)
{
  Word ch;
  DWord screen;
  ch = (Word) (_c & 0x00FF) | 0x0200;
  screen = 0xb8000 + (_y * NUM_COLUMNS + _x) * 2;
  asm("movw %0, (%1)" : : "r"(ch), "r"(screen)); 
}

//imprimeix string a partir de la posició x y
void printk_xy(int x, int y, char *string) 
{
  int i;
  for (i = 0; string[i]; i++)
    printc_xy(x++,y,string[i]);
}

//funció que fa scroll quan arribem al final de la pantalla
void doScroll() 
{
  int ny=2,x=0,oy=3;
  cleanRow(0);
  cleanRow(1); 
	while (oy < NUM_ROWS) 
	{
		x = 0;
		while (x < NUM_COLUMNS) 
		{
			print_word_xy(x,ny,read_xy(x,oy));
			++x;
		}
		++oy;
		++ny;
	}
}


void printc(char c)
{
  Word ch;
  if (c == '\n') 
  {   
    x = 0;
    y++;
	  if (y >= NUM_ROWS) {
		  y=NUM_ROWS -1;
		  doScroll();
		  cleanRow(y);
	  }
  }
  else 
  {
    if (++x >= NUM_COLUMNS)
    {
      x = 0;
      if (++y >= NUM_ROWS)
      {
	      	y = NUM_ROWS-1;
		      doScroll();
		      cleanRow(y);
      }
    }
    ch = (Word) (c & 0x00FF) | 0x0200;
    print_word_xy(x,y,ch);
  }
  __asm__ __volatile__ ( "movb %0, %%al; outb $0xe9" ::"a"(c)); //escriu per consola
}

void printk(char *string)
{
  int i;
  for (i = 0; string[i]; i++)
    printc(string[i]);
}

